﻿using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace HB.Expand
{
    public static class ClassClone
    {
        /// <summary>
        /// 深拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="RealObject"></param>
        /// <returns></returns>
        public static T DeepClone<T>(this T RealObject) where T : class
        {
            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, RealObject);
                objectStream.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(objectStream);
            }
        }
        /// <summary>
        /// 将父类同名属性复制到子类中
        /// </summary>
        /// <typeparam name="TParent"></typeparam>
        /// <typeparam name="TChild"></typeparam>
        /// <param name="parent"></param>
        /// <param name="child"></param>
        /// <param name="IgnoreName"></param>
        public static void CopyToChild<TParent, TChild>(this TParent parent, TChild child, params string[] IgnoreName) where TChild : class, TParent where TParent : class
        {
            parent.CopyToOther(child, IgnoreName);
        }
        /// <summary>
        /// 将子类同名属性复制到父类中
        /// </summary>
        /// <typeparam name="TParent"></typeparam>
        /// <typeparam name="TChild"></typeparam>
        /// <param name="child"></param>
        /// <param name="parent"></param>
        ///         /// <param name="IgnoreName"></param>
        public static void CopyToParent<TParent, TChild>(this TChild child, TParent parent, params string[] IgnoreName) where TChild : class, TParent where TParent : class
        {
            child.CopyToOther(parent, IgnoreName);

        }
        /// <summary>
        /// 将同名属性复制到另一个类（使用者确保属性类型和名称相同）
        /// </summary>
        /// <typeparam name="First"></typeparam>
        /// <typeparam name="Second"></typeparam>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <param name="IgnoreName"></param>
        public static void CopyToOther<First, Second>(this First first, Second second, params string[] IgnoreName)
        {
            var ParentType = typeof(First);
            var Properties = ParentType.GetProperties();
            var ParentType2 = typeof(Second);
            var Properties2 = ParentType2.GetProperties();
            foreach (var p in Properties)
            {
                if (IgnoreName.Contains(p.Name)) { continue; }
                if (p.CanRead)
                {
                    var f = Properties2.FirstOrDefault(zz => zz.Name == p.Name && zz.PropertyType == p.PropertyType);
                    if (f != null)
                    {
                        if (f.CanWrite)
                        {
                            f.SetValue(second, p.GetValue(first, null), null);
                        }
                    }
                }

            }
        }

    }
}
